/** * * * *
 * execCommands tool
 * Ver 1.0 | by Elong | 2022.05.21
 * */
window.excmd = {
  /** * * * * *
   * 文本常规，通用操作
   */
  copy: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("copy", doc, false, param, handelSet);
    if (syntax) doc.execCommand("copy", handelSet, param); // 复制
  },
  cut: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("cut", doc, false, param, handelSet);
    if (syntax) doc.execCommand("cut", handelSet, param); // 剪切
  },
  paste: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("paste", doc, false, param, handelSet);
    if (syntax) doc.execCommand("paste", handelSet, param); //  粘贴
  },
  delete: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("delete", doc, false, param, handelSet);
    if (syntax) doc.execCommand("delete", handelSet, param); // 删除
  },
  undo: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("undo", doc, false, param, handelSet);
    if (syntax) doc.execCommand("undo", handelSet, param); // 撤销
  },
  redo: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("redo", doc, false, param, handelSet);
    if (syntax) doc.execCommand("redo", handelSet, param); // 重做
  },
  selectAll: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("selectAll", doc, false, param, handelSet);
    if (syntax) doc.execCommand("selectAll", handelSet, param); // 全选
  },
  unselect: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("unselect", doc, false, param, handelSet);
    if (syntax) doc.execCommand("unselect", handelSet, param); // 取消选择
  },
  refresh: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("refresh", doc, false, param, handelSet);
    if (syntax) doc.execCommand("refresh", handelSet, param); // 刷新
  },
  stop: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("stop", doc, false, param, handelSet);
    if (syntax) doc.execCommand("stop", handelSet, param); // 停止。
  },
  saveAs: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("saveAs", doc, false, param, handelSet);
    if (syntax) doc.execCommand("saveAs", handelSet, param); // 另存为
  },
  print: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("print", doc, false, param, handelSet);
    if (syntax) doc.execCommand("print", handelSet, param); // 打印
  },
  /** * * * * *
   * 光标相关
   */
  forwardDelete: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("forwardDelete", doc, false, param, handelSet);
    if (syntax) doc.execCommand("forwardDelete", handelSet, param); // 删除光标所在字符（同按键行为）
  },
  insertText: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertText", doc, true, param, handelSet);
    if (syntax) doc.execCommand("insertText", handelSet, param); // % 于光标所在 插入/覆盖所选 字符 (参数为要插入的) 可选
  },
  insertImage: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertImage", doc, true, param, handelSet);
    if (syntax) doc.execCommand("insertImage", handelSet, param); // % 于插入点插入一张图片（删除选中的部分）第三个参数为url 必要
  },
  /** * * * * *
   * 特殊的
   */
  open: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("open", doc, false, param, handelSet);
    if (syntax) doc.execCommand("open", handelSet, param); // 相当于单击文件中的打开按钮
  },
  clearAuthenticationCache: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("clearAuthenticationCache", doc, false, param, handelSet);
    if (syntax) doc.execCommand("clearAuthenticationCache", handelSet, param); // 清除缓存中的所有身份验证凭据 //$仅IE 不建议
  },
  /** * * * * *
   * 编辑器设置
   */
  backColor: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("backColor", doc, true, param, handelSet);
    if (syntax) doc.execCommand("backColor", handelSet, param); // % 文档背景颜色（参数为颜色）
  },
  contentReadOnly: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("contentReadOnly", doc, true, param, handelSet);
    if (syntax) doc.execCommand("contentReadOnly", handelSet, param); // % 文档只读属性（参数为布尔）
  },
  multipleSelection: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("multipleSelection", doc, false, param, handelSet);
    if (syntax) doc.execCommand("multipleSelection", handelSet, param); // 允许当用户按住 Shift 或 Ctrl 键时一次选中多于一个站点可选元素。（参数为布尔//!未证实
  },
  overWrite: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("overWrite", doc, false, param, handelSet);
    if (syntax) doc.execCommand("overWrite", handelSet, param); // 切换文本状态的插入和覆盖（相当于键盘上的 INS）（参数为布尔//!未证实
  },
  liveResize: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("liveResize", doc, false, param, handelSet);
    if (syntax) doc.execCommand("liveResize", handelSet, param); // 迫使 MSHTML 编辑器在缩放或移动过程中持续更新元素外观，而不是只在移动或缩放完成后更新（参数为布尔//!未证实
  },
  enableAbsolutePositionEditor: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("enableAbsolutePositionEditor", doc, false, param, handelSet);
    if (syntax) doc.execCommand("enableAbsolutePositionEditor", handelSet, param); // 绝对定位元素 抓取器开关（参数为布尔//!未证实
  },
  enableInlineTableEditing: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("enableInlineTableEditing", doc, false, param, handelSet);
    if (syntax) doc.execCommand("enableInlineTableEditing", handelSet, param); // 启用或禁用表格行和列插入和删除控件（参数为布尔//!未证实
  },
  enableObjectResizing: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("enableObjectResizing", doc, false, param, handelSet);
    if (syntax) doc.execCommand("enableObjectResizing", handelSet, param); // 启用或禁用图像和其他对象的大小可调整大小手柄（参数为布尔//!未证实
  },
  /** * * * * *
   * 格式化
   */
  formatBlock: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("formatBlock", doc, true, param, handelSet);
    if (syntax) doc.execCommand("formatBlock", handelSet, param); // % 用html标签格式化当前选择行。若已存在则替换（Firefox 中 BLOCKQUOTE 是例外）。参数为标签名（IE需要用<>进行包裹）
  },
  removeFormat: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("removeFormat", doc, false, param, handelSet);
    if (syntax) doc.execCommand("removeFormat", handelSet, param); // 对所选内容去除所有格式
  },
  defaultParagraphSeparator: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("defaultParagraphSeparator", doc, true, param, handelSet);
    if (syntax) doc.execCommand("defaultParagraphSeparator", handelSet, param); // % 更改在可编辑文本区域中创建新段落时使用的段落分隔符，参数为标签名(如p/br...) //$仅火狐 不建议
  },
  insertBrOnReturn: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertBrOnReturn", doc, false, param, handelSet);
    if (syntax) doc.execCommand("insertBrOnReturn", handelSet, param); // 控制当按下Enter键时，是插入 br 标签还是把当前块元素变成两个 //$仅火狐 不建议
  },
  /** * * * * *
   * 布局与对齐
   */
  justifyLeft: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("justifyLeft", doc, false, param, handelSet);
    if (syntax) doc.execCommand("justifyLeft", handelSet, param); // 居左
  },
  justifyCenter: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("justifyCenter", doc, false, param, handelSet);
    if (syntax) doc.execCommand("justifyCenter", handelSet, param); // 居中
  },
  justifyRight: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("justifyRight", doc, false, param, handelSet);
    if (syntax) doc.execCommand("justifyRight", handelSet, param); // 居右
  },
  justifyFull: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("justifyFull", doc, false, param, handelSet);
    if (syntax) doc.execCommand("justifyFull", handelSet, param); // 两端对齐
  },
  insertOrderedList: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertOrderedList", doc, false, param, handelSet);
    if (syntax) doc.execCommand("insertOrderedList", handelSet, param); // 在插入点或者选中文字上创建一个有序列表
  },
  insertUnorderedList: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertUnorderedList", doc, false, param, handelSet);
    if (syntax) doc.execCommand("insertUnorderedList", handelSet, param); // 在插入点或者选中文字上创建一个无序列表。
  },
  indent: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("indent", doc, false, param, handelSet);
    if (syntax) doc.execCommand("indent", handelSet, param); // 缩进选择或插入点所在的行， 在 Firefox 中, 如果选择多行，但是这些行存在不同级别的缩进, 只有缩进最少的行被缩进。
  },
  outdent: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("outdent", doc, false, param, handelSet);
    if (syntax) doc.execCommand("outdent", handelSet, param); // 对光标插入行或者所选行内容减少缩进量。
  },
  insertParagraph: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertParagraph", doc, false, param, handelSet);
    if (syntax) doc.execCommand("insertParagraph", handelSet, param); // 在选择或当前行周围插入一个段落。(IE会在插入点插入一个段落并删除选中的部分.)
  },
  insertHorizontalRule: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertHorizontalRule", doc, false, param, handelSet);
    if (syntax) doc.execCommand("insertHorizontalRule", handelSet, param); // * 在插入点插入一个水平线（删除选中的部分） 最后一个参数为颜色
  },
  insertHTML: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("insertHTML", doc, false, param, handelSet);
    if (syntax) doc.execCommand("insertHTML", handelSet, param); // * 在插入点插入一个HTML字符串（删除选中的部分）。需要一个个HTML字符串作为参数。(IE浏览器不支持)
  },
  "2D-Position": function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("2D-Position", doc, false, param, handelSet);
    if (syntax) doc.execCommand("2D-Position", handelSet, param); // 允许通过拖曳移动绝对定位的对象。
  },
  absolutePosition: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("absolutePosition", doc, false, param, handelSet);
    if (syntax) doc.execCommand("absolutePosition", handelSet, param); // 设定元素的css position:absolute
  },
  /** * * * * *
   * 文字相关
   */
  heading: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("heading", doc, true, param, handelSet);
    console.warn("The method 'heading' is deprecated. It is recommended to use 'fontSize' for better compatibility.");
    if (syntax) doc.execCommand("heading", handelSet, param); // % 添加一个标题标签在光标处或者所选文字上。 需要提供标签名称字符串作为参数 (例如. "H1", "H6"). (将废弃，建议使用fontSize)
  },
  fontSize: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("fontSize", doc, true, param, handelSet);
    if (syntax) doc.execCommand("fontSize", handelSet, param); // % 在插入点或者选中文字部分修改字体大小. 需要提供一个HTML字体尺寸 (1-7) 作为参数。
  },
  bold: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("bold", doc, false, param, handelSet);
    if (syntax) doc.execCommand("bold", handelSet, param); // 开启或关闭选中文字或插入点的粗体字效果。IE浏览器使用 <strong>标签，而不是<b>标签。
  },
  italic: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("italic", doc, false, param, handelSet);
    if (syntax) doc.execCommand("italic", handelSet, param); // 在光标插入点开启或关闭斜体字。 (Internet Explorer 使用 EM 标签，而不是 I )
  },
  foreColor: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("foreColor", doc, true, param, handelSet);
    if (syntax) doc.execCommand("foreColor", handelSet, param); // % 在插入点或者选中文字部分修改字体颜色. 需要提供一个颜色值字符串作为参数。
  },
  hiliteColor: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("hiliteColor", doc, true, param, handelSet);
    if (syntax) doc.execCommand("hiliteColor", handelSet, param); // % 更改选择或插入点的背景颜色。需要一个颜色值字符串作为值参数传递。 UseCSS 必须开启此功能。(IE浏览器不支持)
  },
  decreaseFontSize: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("decreaseFontSize", doc, false, param, handelSet);
    if (syntax) doc.execCommand("decreaseFontSize", handelSet, param); // 给选中文字加上 <small> 标签，或在选中点插入该标签。(IE浏览器不支持)
  },
  increaseFontSize: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("increaseFontSize", doc, false, param, handelSet);
    if (syntax) doc.execCommand("increaseFontSize", handelSet, param); // 在选择或插入点周围添加一个BIG标签。(IE浏览器不支持)
  },
  fontName: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("fontName", doc, true, param, handelSet);
    if (syntax) doc.execCommand("fontName", handelSet, param); // % 在插入点或者选中文字部分修改字体名称. 需要提供一个字体名称字符串 (例如："Arial")作为参数。
  },
  strikeThrough: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("strikeThrough", doc, false, param, handelSet);
    if (syntax) doc.execCommand("strikeThrough", handelSet, param); // 在光标插入点开启或关闭删除线。
  },
  underline: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("underline", doc, false, param, handelSet);
    if (syntax) doc.execCommand("underline", handelSet, param); // 在光标插入点开启或关闭下划线。
  },
  subscript: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("subscript", doc, false, param, handelSet);
    if (syntax) doc.execCommand("subscript", handelSet, param); // 在光标插入点开启或关闭下角标。
  },
  superscript: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("superscript", doc, false, param, handelSet);
    if (syntax) doc.execCommand("superscript", handelSet, param); // 在光标插入点开启或关闭上角标。
  },
  createLink: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("createLink", doc, true, param, handelSet);
    console.log(syntax, handelSet, param);
    if (syntax) doc.execCommand("createLink", handelSet, param); // % 将选中内容创建为一个锚链接。这个命令需要一个hrefURI字符串作为参数值传入。URI必须包含至少一个字符，例如一个空格。（浏览器会创建一个空链接）
  },
  unlink: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("unlink", doc, false, param, handelSet);
    if (syntax) doc.execCommand("unlink", handelSet, param); // 去除所选的锚链接的<a>标签
  },
  createBookmark: function (doc, param, handelSet) {
    var syntax = this.excmdSyntaxChecker("createBookmark", doc, true, param, handelSet);
    if (syntax) doc.execCommand("createBookmark", handelSet, param); // % 设置指定锚点为书签
  },
  excmdSyntaxChecker: function (fnName, doc, isMust, param, handelSet) {
    if (!doc) {
      console.warn(`Syntax Err: missing "doc" of command '${fnName}'`);
      return false;
    } else if (isMust && typeof param != "boolean" && !param && !handelSet) {
      console.warn(`Syntax Err: missing parameter of command ${fnName}`);
      return false;
    } else return true; // 语法校验
  },
  length: function () {
    return Object.keys(this).length - 2; // 获取属性长度
  }
};
